﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using static System.Collections.Specialized.BitVector32;
using static System.Net.Mime.MediaTypeNames;


#region 文件信息
/****************************************************************
*	公司名称：福建力和行智能科技有限公司
*   作    者：Jeff
*   CLR 版本：4.0.30319.42000
*   创建时间：12/20/2024 3:40:44 PM
*	用 户 名：zheqichen 
*   描述说明：
*
*   修改历史：
*		1）	修 改 人：
*			修改日期：
*			修改内容：			
*
*****************************************************************/
#endregion

namespace Lhxzn.LangExtractor
{
    /// <summary>
    /// 类    名:IniFile
    /// 描    述:
    /// 修改时间:12/20/2024 3:40:44 PM
    /// </summary>
    public class IniFile: ICloneable
    {

        #region static

        [DllImport("kernel32")]
        private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);


        public static string ReadValueFromPath(string iniPath, string Section, string Key)
        {
            StringBuilder temp = new StringBuilder(500);
            int i = GetPrivateProfileString(Section, Key, "", temp, 500, iniPath);
            return temp.ToString();
        }

        public static void WriteValueToPath(string iniPath, string Section, string Key, string Value)
        {
            WritePrivateProfileString(Section, Key, Value, iniPath);
        }

        #endregion


        #region class

        /// <summary>
        /// 键值数据
        /// </summary>
        public class KeyData : ICloneable
        {
            /// <summary>
            /// 数值内容
            /// </summary>
            public string Value { get; set; }

            /// <summary>
            /// 注释
            /// </summary>
            public string[] Comments { get; set; }


            public KeyData() : this(string.Empty, null)
            {

            }

            public KeyData(string value) : this(value, null)
            {

            }


            public KeyData(string value, string[] comments)
            {
                this.Value = value;
                this.Comments = comments;
            }

            public static implicit operator string(KeyData t)
            {
                return t.Value;
            }

            public static implicit operator KeyData(string str)
            {
                return new KeyData(str);
            }

            public object Clone()
            {
                return this.MemberwiseClone();
            }

            public override string ToString()
            {
                return Value.ToString();
            }
        }

        #endregion


        #region 属性

        protected Dictionary<string, Dictionary<string, KeyData>> m_dictIniCache;

        /// <summary>
        /// 获取INI文件中的所有节点
        /// </summary>
        public string[] Sections
        {
            get
            {
                return m_dictIniCache.Keys.ToArray();
            }
        }


        /// <summary>
        /// 获取节点内的键存储的值
        /// </summary>
        /// <param name="section"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public string this[string section, string key]
        {
            get
            {
                return ReadValue(section, key);
            }
            set
            {
                WriteValue(section, key, value);
            }
        }


        /// <summary>
        /// 获取节点的键值集合
        /// </summary>
        /// <param name="section"></param>
        /// <returns></returns>
        public string[] this[string section]
        {
            get
            {
                return GetKeys(section);
            }
        }

        /// <summary>
        /// 是否记录不存在的键值
        /// </summary>
        public bool IsLogNonexistent { get; set; }


        /// <summary>
        /// 文件路径
        /// </summary>
        public string FilePath { get; set; }


        /// <summary>
        /// 编码格式
        /// </summary>
        public Encoding Encoding { get; set; }

        #endregion

        #region 构造函数

        public IniFile(string filepath) : this(filepath, Encoding.UTF8)
        {

        }


        public IniFile(string filepath, Encoding code)
        {
            FilePath = filepath;
            Encoding = code;
            m_dictIniCache = new Dictionary<string, Dictionary<string, KeyData>>();
        }


        #endregion

        #region 方法
        public string[] GetKeys(string Section)
        {
            return m_dictIniCache.ContainsKey(Section) ? m_dictIniCache[Section].Keys.ToArray() : new string[] { };
        }


        public bool ContainsSection(string Section)
        {
            return !string.IsNullOrEmpty(Section) && m_dictIniCache.ContainsKey(Section);
        }

        public bool ContainsKey(string Section, string Key)
        {
            return ContainsSection(Section) && m_dictIniCache[Section].ContainsKey(Key);
        }

        public string ReadValue(string Section, string Key)
        {
            return ReadValue(Section, Key, Key);
        }


        /// <summary>
        /// 读取键值,可传入默认值
        /// </summary>
        /// <param name="Section"></param>
        /// <param name="Key"></param>
        /// <param name="strDefault"></param>
        /// <returns></returns>
        public virtual string ReadValue(string Section, string Key, string strDefault)
        {
            string res = Key;
            if (ContainsKey(Section, Key))
            {
                res = m_dictIniCache[Section][Key];
            }
            else
            {
                res = strDefault;
                if (IsLogNonexistent)
                {
                    WriteValue(Section, Key, res);
                }

            }
            return res;
        }



        public int ReadValueInt(string Section, string Key, int iDefault = 0)
        {
            try
            {
                return Convert.ToInt32(ReadValue(Section, Key));
            }
            catch
            {

                return iDefault;
            }
        }
        public double ReadValueDouble(string Section, string Key, double dbDefault = 0)
        {
            double res;
            if (double.TryParse(ReadValue(Section, Key), out res))
            {
                return res;
            }
            else
            {
                return dbDefault;
            }

        }
        public void WriteValue(string Section, string Key, string Value)
        {
            if (!m_dictIniCache.ContainsKey(Section))
            {
                m_dictIniCache[Section] = new Dictionary<string, KeyData>();
            }
            m_dictIniCache[Section][Key] = Value;
        }

        public void WriteValue(string Section, string Key, int Value)
        {
            WriteValue(Section, Key, Value.ToString());
        }

        public void WriteValue(string Section, string Key, double Value, uint Decimal = 3)
        {
            WriteValue(Section, Key, Value.ToString("f" + Decimal));
        }
        public void DeleteSection(string section)
        {
            if (m_dictIniCache.ContainsKey(section))
                m_dictIniCache.Remove(section);
        }


        public void Clear()
        {
            m_dictIniCache.Clear();
        }

        public void DeleteKey(string section, string key)
        {
            if (m_dictIniCache.ContainsKey(section) &&
                m_dictIniCache[section].ContainsKey(key))
            {
                m_dictIniCache[section].Remove(key);
            }
        }

        /// <summary>
        /// 写入字符流
        /// </summary>
        public virtual void WriteStream()
        {
            string text= GetText();
            File.WriteAllText(FilePath, text, this.Encoding);
        }

        /// <summary>
        /// 写入字符流
        /// </summary>
        public virtual void WriteStream(string path)
        {
            string text = GetText();
            File.WriteAllText(path, text, this.Encoding);
        }

        public virtual string GetText()
        {
            StringBuilder Buffer = new StringBuilder();
            foreach (string Section in m_dictIniCache.Keys)
            {
                Buffer.AppendLine(string.Format("[{0}]", Section));
                foreach (string key in m_dictIniCache[Section].Keys)
                {
                    KeyData value = m_dictIniCache[Section][key];
                    if (value.Comments != null)
                    {
                        foreach (string comment in value.Comments)
                        {
                            Buffer.AppendLine(";" + comment);
                        }
                    }
                    if (key == "创建椭圆")
                    {
                        int i= 0;
                    }
                    Buffer.AppendLine(string.Format("{0}={1}", key, value.Value));
                }
            }
            return Buffer.ToString();
        }

        public virtual string GetSectionText(string Section)
        {
            StringBuilder Buffer = new StringBuilder();
            if (m_dictIniCache.ContainsKey(Section))
            {
                Buffer.AppendLine(string.Format("[{0}]", Section));
                foreach (string key in m_dictIniCache[Section].Keys)
                {
                    KeyData value = m_dictIniCache[Section][key];
                    if (value.Comments != null)
                    {
                        foreach (string comment in value.Comments)
                        {
                            Buffer.AppendLine(";" + comment);
                        }
                    }
                    Buffer.AppendLine(string.Format("{0}={1}", key, value.Value));
                }
            }
            return Buffer.ToString();
        }


        /// <summary>
        /// 读取字符流
        /// </summary>
        public virtual void ReadStream()
        {
            FileStream fileStream = new FileStream(FilePath, FileMode.OpenOrCreate);
            StreamReader reader = new StreamReader(fileStream, this.Encoding);
            string LastSection = string.Empty;
            List<string> comments = new List<string>();
            while (!reader.EndOfStream)
            {
                string str = reader.ReadLine(), section;
                str = ReplaceIllegalCharactersWithNewline(str);
                if (string.IsNullOrEmpty(str))
                {
                    //空行跳过
                    continue;
                }

                string key, value, comment;

                if (IsSection(str, out section))
                {
                    //是节点，就添加节点
                    if (!m_dictIniCache.ContainsKey(section))
                        m_dictIniCache[section] = new Dictionary<string, KeyData>();
                    LastSection = section;
                }
                else if (IsComments(str, out comment))
                {
                    comments.Add(comment);
                }
                else if (IsKeyValuePair(str, out key, out value))
                {
                    //是键值对，就添加键值对
                    if (!string.IsNullOrEmpty(LastSection))
                    {
                        m_dictIniCache[LastSection][key] = value;
                        if (comments.Count > 0)
                        {
                            m_dictIniCache[LastSection][key].Comments = comments.ToArray();
                        }

                    }
                    comments.Clear();
                }
            }
            reader.Close();
            fileStream.Close();
        }

        public virtual void Reload(string txt)
        {
            m_dictIniCache.Clear();
            ReadText(txt);
        }

        public virtual void ReloadSection(string txt,string sectionName)
        {
            if(m_dictIniCache.ContainsKey(sectionName))
                m_dictIniCache.Remove(sectionName);
            ReadText(txt);
        }

        public virtual void ReadText(string txt)
        {
            string LastSection = string.Empty;
            List<string> comments = new List<string>();
            txt=ReplaceIllegalCharactersWithNewline(txt);
            string[] lines = txt.Split('\n');
            for (int i=0;i<lines.Length;i++)
            {
                string str = lines[i], section;

                if (string.IsNullOrEmpty(str))
                {
                    //空行跳过
                    continue;
                }

                string key, value, comment;

                if (IsSection(str, out section))
                {
                    //是节点，就添加节点
                    if (!m_dictIniCache.ContainsKey(section))
                        m_dictIniCache[section] = new Dictionary<string, KeyData>();
                    LastSection = section;
                }
                else if (IsComments(str, out comment))
                {
                    comments.Add(comment);
                }
                else if (IsKeyValuePair(str, out key, out value))
                {
                    //是键值对，就添加键值对
                    if (!string.IsNullOrEmpty(LastSection))
                    {
                        m_dictIniCache[LastSection][key] = value;
                        if (comments.Count > 0)
                        {
                            m_dictIniCache[LastSection][key].Comments = comments.ToArray();
                        }

                    }
                    comments.Clear();
                }
            }
        }

        static string ReplaceIllegalCharactersWithNewline(string text)
        {
            char[] result = new char[text.Length];
            int index = 0;

            foreach (char ch in text)
            {
                if (char.IsControl(ch))
                {
                    result[index++] = '\n';
                }
                else
                {
                    result[index++] = ch;
                }
            }
            return new string(result, 0, index);
        }

        /// <summary>
        /// 与别的IniFile合并
        /// </summary>
        /// <param name="other"></param>
        public virtual void MergeWith(IniFile other)
        {
            foreach (var section in other.m_dictIniCache)
            {
                if (!m_dictIniCache.ContainsKey(section.Key))
                {
                    var newSection = new Dictionary<string, KeyData>();
                    foreach (var kvp in section.Value)
                    {
                        newSection[kvp.Key] = new KeyData() { Value = kvp.Key };
                    }
                    m_dictIniCache[section.Key] = newSection;
                }
                else
                {
                    foreach (var kvp in section.Value)
                    {
                        if (!m_dictIniCache[section.Key].ContainsKey(kvp.Key))
                        {
                            KeyData keyValue = new KeyData() { Value = kvp.Key };
                            m_dictIniCache[section.Key][kvp.Key] = keyValue;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 与别的IniFile合并
        /// </summary>
        /// <param name="other"></param>
        public virtual void MergeWith(IniFile other, out List<string> annotations)
        {
            annotations = new List<string>();
            foreach (var section in other.m_dictIniCache)
            {
                if (!m_dictIniCache.ContainsKey(section.Key))
                {
                    var newSection = new Dictionary<string, KeyData>();
                    foreach (var kvp in section.Value)
                    {
                        newSection[kvp.Key] = new KeyData() { Value = kvp.Key };
                        annotations.Add($"{kvp.Key}={kvp.Key}");
                    }
                    m_dictIniCache[section.Key] = newSection;
                }
                else
                {
                    foreach (var kvp in section.Value)
                    {
                        if (!m_dictIniCache[section.Key].ContainsKey(kvp.Key))
                        {
                            KeyData keyValue =new KeyData() { Value = kvp.Key };
                            var data = m_dictIniCache[section.Key];
                            annotations.Add($"{kvp.Key}={kvp.Key}");
                            m_dictIniCache[section.Key][kvp.Key] = keyValue;
                        }
                    }
                }
            }
        }


        /// <summary>
        /// 判断是否是键值对
        /// </summary>
        /// <param name="line"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool IsKeyValuePair(string line, out string key, out string value)
        {
            int index = line.IndexOf('=');
            if (index > 0)
            {
                key = line.Substring(0, index);
                value = line.Substring(index + 1);
                return true;
            }
            else
            {
                key = null;
                value = null;
                return false;
            }
        }


        /// <summary>
        /// 判断该行是否是注释
        /// </summary>
        /// <param name="line"></param>
        /// <param name="comment"></param>
        /// <returns></returns>
        public static bool IsComments(string line, out string comment)
        {
            if (line.Length > 0)
            {
                comment = line.Substring(1);
                return line[0] == ';';
            }
            else
            {
                comment = null;
                return false;
            }
        }

        /// <summary>
        /// 判断是否是节点
        /// </summary>
        /// <param name="str"></param>
        /// <param name="section"></param>
        /// <returns></returns>
        public static bool IsSection(string str, out string section)
        {
            bool res = false;
            section = string.Empty;
            if (str.Length <= 3 || str[0] != '['|| !str.EndsWith(']')) return res;
            res = true;
            int i = 1;
            while (i < str.Length && str[i] != ']')
            {
                section += str[i];
                i++;
            }
            if (i == str.Length)
            {
                res = false;
                section = string.Empty;
            }
            return res;
        }

        public object Clone()
        {
            IniFile iniFile = new IniFile(this.FilePath);

            Dictionary<string, Dictionary<string, KeyData>> dict_data = new Dictionary<string, Dictionary<string, KeyData>>();
            foreach (KeyValuePair<string, Dictionary<string, KeyData>> kvp in this.m_dictIniCache)
            {
                dict_data[kvp.Key] = new Dictionary<string, KeyData>();
                foreach (KeyValuePair<string, KeyData> kvp2 in kvp.Value)
                {
                    dict_data[kvp.Key][kvp2.Key] = kvp2.Value.Clone() as KeyData;
                }
            }
            iniFile.m_dictIniCache = dict_data;
            return iniFile;
        }

        #endregion
    }
}
